אספר בקצרה על commit&rollback, אפשרות מעולה ליצור מחויבות בין כמה שאילתות של מסד נתונים המשולבות בקוד ה-PHP שירוצו יחדיו בכל מצב.
שלום לכולם,
אתחיל מסיפור. היה היה (ועדיין קיים, ויהיה קיים) אתר בשם איזרהסולג'רס, משחק דפדפן, עם כמות עצומה של משתמשים, ובגלל אופי האתר, גם כמות אדירה של שאילתות בשניה!
בימים טובים, הכל היה חלק והייתי שמח כשהשרת היה סוחב, והיו גם ימים פחות טובים, בהם השרת קצת קרטע, ואפילו קרס.
חשבתם פעם מה קורה לשאילתה כשהשרת קורס באמצע? גם לא חייב לקרוס, יכול סתם להיתקע. יותר מזה, בדקתי ויצא לי ש-2 שאילתות מנוגדות שמתבצעות באותה השניה גורמות גם כן לבעיות.
אז מה עושים?
מה היה עושה בנק אילו היה לו שתי שאילתות? לדוגמה, להעביר כסף מא' לב'?
אם א' העביר וקרה משהו לשאילתה וב' לא קיבל, אבל לא' ירד הכסף?
לפעולה כזו יש שם מקצועי - טרנסקציות (Transactions), ול-MySQL יש אפשרות "לחייב" שתי שאילתות לרוץ בכל מקרה!
אם קרה ואחת מהן נתקעה או לא התבצעה, גם האחרת לא מתבצעת, וכך א' לא מאבד את הכסף שלו!
אני לא אכנס למבנה מסד הנתונים, ואיך הקריאה ממנו מתבצעת, אבל חשוב לדעת שהאפשרות קיימת רק בטבלאות המשתמשות במנוע InnoDB.
(אתם יכולים לשנות את המנוע של הטבלה ממש בקלות.)
אראה לכם כיצד COMMIT עובד.
// כאן אנחנו מתחילים את הטרנסאקציה
$db->query('BEGIN');
$query1 = $db->query("SELECT money FROM users WHERE id='1'");
$data = $db->fetchAssoc($query1);
$query2 = $db->query("UPDATE users set money=money + {$data['money']} WHERE id='2'");
$query3 = $db->query("UPDATE users set money=money - {$data['money']} WHERE id='1'");
if($query1 && $query2 && $query3){
//אם הכל התבצע, אנו נחייב את השאילתות האלה
$db->query('COMMIT');
} else {
// אם קרה משהו באמצע, תחזיר לקדמותו
$db->query('ROLLBACK');
}
$db->query('BEGIN');
$query1 = $db->query("SELECT money FROM users WHERE id='1'");
$data = $db->fetchAssoc($query1);
$query2 = $db->query("UPDATE users set money=money + {$data['money']} WHERE id='2'");
$query3 = $db->query("UPDATE users set money=money - {$data['money']} WHERE id='1'");
if($query1 && $query2 && $query3){
//אם הכל התבצע, אנו נחייב את השאילתות האלה
$db->query('COMMIT');
} else {
// אם קרה משהו באמצע, תחזיר לקדמותו
$db->query('ROLLBACK');
}
כך אנו מחייבים כמה שאילתות להתבצע יחדיו או אף אחת מהן; זה מתאים לכל מי שמפתח אתר לבנק, או סתם אתר שצריך להעביר זהב משחקן אחד לאחר ונתקל בעניין דומה, או סתם רוצה להיות מקצועי יותר. :)
שוב אני מדגיש, זה עובד על טבלאות שעל גבי מנוע InnoDB, שלעומת MyISAM הוא מאפשר טרנסאקציות.
מי שרוצה עוד מדריכים חופרים בנושאי ה-SQL מוזמן לבקש,
בהצלחה! :)
תגובות לכתבה:
מדריך מעולה, תודה.
הוסיף לומר, שלמחלקות mysqlI ו PDO יש תמיכה מובנית בטראנזקציות, ככה שאפשר לקרוא למטודה מסוימת של המחלקה במקום לעשות את שאילתות ה begin/commit/rollback באופן עצמאי.
רוב השימוש שלכם בטרנזקציות יהיה בתוך בלוקים של try/catch שבמקרה ואחת השאילתות לא הצליחה
יהיה צורך לבטל את ביצועם של כל שאר.
שימו לב, טראנזקציות הם פר חיבור אחד למסד. כלומר לא ניתן לבצע שני חיבורים שונים למסד ולהכניס אותם לאותה טרנזקציה. תצטרכו ליצור שני טרנזקציות נפרדות ולשניהם יחד לעשות קומיט או לשניהם יחד רולבאק.
רומן, תודה :)
תודה רבה, למדתי דבר נוסף!
אני מת לדעת את אופן הפעולה של המסדים בFACEBOOK, הרי הם לא משתמשים בMYSQL נכון?
לפי דעתי הם משתמשים בהכל תלוי בתוכן,
אולי חלק הם שומרים בmysql רגיל כי זה מסד רלציוני,
מצד שני את ההמלצות חברים הם בטח עושים במסד מסוג גראפ,
כגון neo4j , ובטח בשביל המידע השוטף יש להם את קסנדרה,
אם אני לא טועה זה השם, זה מסד מסוג nosql שהם המציאו
אם אני עושה טרנזקציה א' המכילה שאילתות 1 ו2, וטרנזקציה ב' המכילה שאילתות 3 ו4 , נניח ב' מופעלת בדיוק לפני ש1 מסתיים , אז זה ימתין עד ש2 יסיים ורק אז ישחרר את 3 ו4? או שיבצע קודם את 3?